// SPDX-FileCopyrightText: Adam Evyčędo
//
// SPDX-License-Identifier: GPL-3.0-or-later

package xyz.apiote.bimba.czwek.settings.feeds

import android.content.Context
import android.content.DialogInterface
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.materialswitch.MaterialSwitch
import com.google.android.material.textview.MaterialTextView
import xyz.apiote.bimba.czwek.R
import xyz.apiote.bimba.czwek.repo.FeedInfo
import java.time.format.DateTimeFormatter


class BimbaFeedInfoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
	val root: View = itemView.findViewById(R.id.feed)
	val switch: MaterialSwitch = itemView.findViewById(R.id.feed_switch)
	val name: TextView = itemView.findViewById(R.id.feed_name)
	val switchContainer: ConstraintLayout = itemView.findViewById(R.id.feed_switch_container)

	companion object {
		fun bind(
			feed: FeedInfo,
			feedSettings: FeedSettings?,
			holder: BimbaFeedInfoViewHolder?,
			context: Context,
			onClickListener: (String) -> Unit,
			onCheckedChangeListener: (String, Boolean) -> Unit
		) {
			val colorAttr = if (feed.cached) {
				com.google.android.material.R.attr.colorOnSurfaceVariant
			} else {
				com.google.android.material.R.attr.colorOnSurface
			}
			holder?.name?.setTextColor(
				context.theme.obtainStyledAttributes(
					R.style.Theme_Bimba, intArrayOf(colorAttr)
				).getColor(0, 0)
			)
			holder?.root?.setOnClickListener {
				onClickListener(feed.id)
			}
			holder?.name?.text = feed.name
			if (feedSettings != null) {
				holder?.switchContainer?.visibility = View.VISIBLE
				holder?.switch?.apply {
					isChecked = feedSettings.enabled
					setOnCheckedChangeListener { _, isChecked ->
						onCheckedChangeListener(feed.id, isChecked)
					}
				}
			}
		}
	}
}

class BimbaFeedInfoAdapter(
	private val inflater: LayoutInflater,
	private var feeds: List<FeedInfo>,
	private var feedsSettings: FeedsSettings,
	private val context: Context,
	private val onClickListener: ((String) -> Unit),
	private val onEnabledChangedListener: ((String, Boolean) -> Unit)
) :
	RecyclerView.Adapter<BimbaFeedInfoViewHolder>() {

	class DiffUtilCallback(
		private val oldFeeds: List<FeedInfo>,
		private val oldSettings: FeedsSettings,
		private val newFeeds: List<FeedInfo>,
		private val newSettings: FeedsSettings
	) : DiffUtil.Callback() {
		override fun getOldListSize() = oldFeeds.size

		override fun getNewListSize() = newFeeds.size

		override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) =
			oldFeeds[oldItemPosition].id == newFeeds[newItemPosition].id

		override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
			val oldItem = oldFeeds[oldItemPosition]
			val oldSetting = oldSettings.settings[oldItem.id]
			val newItem = newFeeds[newItemPosition]
			val newSetting = newSettings.settings[newItem.id]
			return oldItem.cached == newItem.cached && oldItem.name == newItem.name && oldSetting?.enabled == newSetting?.enabled
		}
	}

	override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BimbaFeedInfoViewHolder {
		val rowView = inflater.inflate(R.layout.feedinfo, parent, false)
		return BimbaFeedInfoViewHolder(rowView)
	}

	override fun onBindViewHolder(holder: BimbaFeedInfoViewHolder, position: Int) {
		val feed = feeds[position]
		BimbaFeedInfoViewHolder.bind(
			feed,
			feedsSettings.settings[feed.id],
			holder,
			context,
			onClickListener,
			onEnabledChangedListener
		)
	}

	override fun getItemCount(): Int = feeds.size

	fun getItemPosition(feedID: String): Int {
		return feeds.indexOfFirst { it.id == feedID }
	}

	fun update(items: List<FeedInfo>?, settings: FeedsSettings?, notify: Boolean) {
		val diffCallback = DiffUtilCallback(
			feeds,
			feedsSettings,
			items?.sortedBy { it.name } ?: feeds,
			settings ?: feedsSettings
		)
		val diff = DiffUtil.calculateDiff(diffCallback)
		if (items != null) {
			feeds = items.sortedBy { it.name }
		}
		if (settings != null) {
			feedsSettings = settings
		}
		if (notify) {
			diff.dispatchUpdatesTo(this)
		}
	}
}

class FeedBottomSheet(
	private val feedID: String,
	private val feeds: Map<String, FeedInfo>,
	private val feedsSettings: FeedsSettings,
	private val onDismiss: (FeedSettings?) -> Unit
) :
	BottomSheetDialogFragment() {
	companion object {
		const val TAG = "DepartureBottomSheet"
	}

	private var settings: FeedSettings? = null

	override fun onCreateView(
		inflater: LayoutInflater,
		container: ViewGroup?,
		savedInstanceState: Bundle?
	): View {
		val content = inflater.inflate(R.layout.feed_bottom_sheet, container, false)
		val feed = feeds[feedID]!!
		var settings = feedsSettings.settings[feedID]
		content.findViewById<MaterialTextView>(R.id.title).text = feed.name
		content.findViewById<MaterialTextView>(R.id.description).text = feed.description
		content.findViewById<MaterialTextView>(R.id.outdated_info_warning).visibility =
			if (feed.cached) {
				View.VISIBLE
			} else {
				View.GONE
			}
		if (feed.validSince != null && feed.validTill != null) {
			content.findViewById<MaterialTextView>(R.id.timetable_validity).apply {
				visibility = View.VISIBLE
				text = getString(
					R.string.current_timetable_validity,
					feed.validSince.format(DateTimeFormatter.ISO_LOCAL_DATE),
					feed.validTill.format(DateTimeFormatter.ISO_LOCAL_DATE)
				)
			}
		}
		content.findViewById<MaterialTextView>(R.id.attribution).text = feed.attribution
		content.findViewById<MaterialTextView>(R.id.update_time).text =
			getString(R.string.last_update, feed.formatDate())
		content.findViewById<MaterialSwitch>(R.id.onlineSwitch).apply {
			isChecked = settings?.useOnline ?: false
			setOnCheckedChangeListener { _, isChecked ->
				settings = settings?.copy(useOnline = isChecked) ?: FeedSettings(
					enabled = true,
					useOnline = isChecked
				)
				this@FeedBottomSheet.settings = settings
			}
		}
		return content
	}

	override fun onDismiss(dialog: DialogInterface) {
		onDismiss(settings)
		settings = null
		super.onDismiss(dialog)
	}
}